home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 16 / CU Amiga Magazine's Super CD-ROM 16 (1997-10-16)(EMAP Images)(GB)[!][issue 1997-11].iso / CUCD / Graphics / Ghostscript / source / gdevpdfi.c < prev    next >
C/C++ Source or Header  |  1997-06-02  |  24KB  |  783 lines

  1. /* Copyright (C) 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevpdfi.c */
  20. /* Image handling for PDF-writing driver */
  21. #include "memory_.h"
  22. #include "gx.h"
  23. #include "gserrors.h"
  24. #include "gsflip.h"
  25. #include "gdevpdfx.h"
  26. #include "gxcspace.h"
  27. #include "gxistate.h"
  28. #include "strimpl.h"
  29. #include "sa85x.h"
  30. #include "scfx.h"
  31. #include "srlx.h"
  32.  
  33. /* We need color space types for constructing temporary color spaces. */
  34. extern const gs_color_space_type
  35.   gs_color_space_type_DeviceGray,
  36.   gs_color_space_type_DeviceRGB,
  37.   gs_color_space_type_DeviceCMYK,
  38.   gs_color_space_type_Indexed;
  39.  
  40. /* ---------------- Utilities ---------------- */
  41.  
  42. /* ------ Binary data ------ */
  43.  
  44. /* Define the structure for the filters for writing binary data. */
  45. typedef struct pdf_binary_writer_s {
  46.     stream *strm;
  47.     stream es;        /* no state for A85E */
  48.     byte encode_buf[256];
  49.     stream cs;        /* client provides (initialized) state */
  50.     byte compress_buf[256];
  51. } pdf_binary_writer;
  52.  
  53. private const stream_procs filter_write_procs =
  54. {    s_std_noavailable, s_std_noseek, s_std_write_reset,
  55.     s_std_write_flush, s_filter_close
  56. };
  57.  
  58. /* Begin writing binary data. */
  59. /* If css is not NULL, it is the compressor stream state. */
  60. private int
  61. pdf_begin_binary(gx_device_pdf *pdev, pdf_binary_writer *pbw,
  62.   stream_state *css)
  63. {    stream *s = pdev->strm;
  64.  
  65.     /* If not binary, set up the encoding stream. */
  66.     if ( !pdev->binary_ok )
  67.       { stream *es = &pbw->es;
  68.         s_std_init(es, pbw->encode_buf, sizeof(pbw->encode_buf),
  69.                &filter_write_procs, s_mode_write);
  70.         es->template = &s_A85E_template;
  71.         es->procs.process = es->template->process;
  72.         es->strm = s;
  73.         s = es;
  74.       }
  75.     /* If compressing, set up the compression stream. */
  76.     if ( css )
  77.       { stream *cs = (stream *)&pbw->cs;
  78.         const stream_template *template = css->template;
  79.         s_std_init(cs, pbw->compress_buf, sizeof(pbw->compress_buf),
  80.                &filter_write_procs, s_mode_write);
  81.         css->memory = pdev->pdf_memory;
  82.         cs->state = css;
  83.         cs->procs.process = template->process;
  84.         if ( template->init )
  85.           (*template->init)(css);
  86.         cs->strm = s;
  87.         s = cs;
  88.       }
  89.     pbw->strm = s;
  90.     return 0;
  91. }
  92.  
  93. /* Finish writing binary data. */
  94. private int
  95. pdf_end_binary(gx_device_pdf *pdev, pdf_binary_writer *pbw)
  96. {    stream *s = pbw->strm;
  97.  
  98.     /* Close the filters in reverse order. */
  99.     /* Stop before we try to close the file stream. */
  100.     while ( s != pdev->strm )
  101.       { stream *next = s->strm;
  102.         /* We have to open-code sclose, because we want to release */
  103.         /* the stream state but not try to free it. */
  104.         stream_state *st = s->state;
  105.         stream_proc_release((*release)) = st->template->release;
  106.         (*s->procs.close)(s);
  107.         if ( release != 0 )
  108.           (*release)(st);
  109.         s = next;
  110.       }
  111.     sflush(s);    /* flush the file stream buffer */
  112.     return 0;
  113. }
  114.  
  115. /* ------ Images ------ */
  116.  
  117. /* Define the long and short versions of the keys in an image dictionary, */
  118. /* and other strings for images. */
  119. typedef struct pdf_image_names_s {
  120.   const char *ASCII85Decode;
  121.   const char *BitsPerComponent;
  122.   const char *CalCMYK;
  123.   const char *CalGray;
  124.   const char *CalRGB;
  125.   const char *CCITTFaxDecode;
  126.   const char *ColorSpace;
  127.   const char *Decode;
  128.   const char *DecodeParms;
  129.   const char *DeviceCMYK;
  130.   const char *DeviceGray;
  131.   const char *DeviceRGB;
  132.   const char *Filter;
  133.   const char *Height;
  134.   const char *ImageMask;
  135.   const char *Indexed;
  136.   const char *Interpolate;
  137.   const char *Width;
  138. } pdf_image_names;
  139. private const pdf_image_names image_names_full = {
  140.   "/ASCII85Decode", "/BitsPerComponent",
  141.   "/CalCMYK", "/CalGray", "/CalRGB", "/CCITTFaxDecode", "/ColorSpace",
  142.   "/Decode", "/DecodeParms", "/DeviceCMYK", "/DeviceGray", "/DeviceRGB",
  143.   "/Filter", "/Height", "/ImageMask", "/Indexed", "/Interpolate", "/Width",
  144. };
  145. private const pdf_image_names image_names_short = {
  146.   "/A85", "/BPC",
  147.     /* We need CalRGB to work around a bug in some Adobe products. */
  148.   "/CC", "/CG", /*"/CR"*/ "/CalRGB", "/CCF", "/CS",
  149.   "/D", "/DP", "/CMYK", "/G", "/RGB",
  150.   "/F", "/H", "/IM", "/I", "/I", "/W",
  151. };
  152.  
  153. /* Write out image parameters for either an in-line image or image resource. */
  154. private int
  155. pdf_write_image_params(gx_device_pdf *pdev, const gs_image_t *pim,
  156.   const char *filter_name, const char *decode_parms,
  157.   const pdf_image_names *pin)
  158. {    stream *s = pdev->strm;
  159.     const gs_color_space *pcs = pim->ColorSpace;
  160.     const char *cs_name;
  161.     int num_components = 0;
  162.     float indexed_decode[2];
  163.     const float *default_decode = NULL;
  164.     char cal_cs_name[50];
  165.     
  166.     if ( pim->ImageMask )
  167.       { pprints1(s, "%s true", pin->ImageMask);
  168.         pdev->procsets |= ImageB;
  169.         num_components = 1;
  170.       }
  171.     else
  172.       { const gs_color_space *pbcs = pcs;
  173.         const gs_indexed_params *pip = 0;
  174.  
  175.         pputs(s, pin->ColorSpace);
  176. csw:        switch ( gs_color_space_get_index(pbcs) )
  177.           {
  178.           case gs_color_space_index_DeviceGray:
  179.         pdev->procsets |= ImageB;
  180.         cs_name = pin->DeviceGray;
  181.         break;
  182.           case gs_color_space_index_DeviceRGB:
  183.         pdev->procsets |= ImageC;
  184.         cs_name = pin->DeviceRGB;
  185.         break;
  186.           case gs_color_space_index_DeviceCMYK:
  187.         pdev->procsets |= ImageC;
  188.         cs_name = pin->DeviceCMYK;
  189.         break;
  190.           case gs_color_space_index_CIEA:
  191.         pdev->procsets |= ImageB;
  192.         cs_name = pin->CalGray;
  193. cal:        sprintf(cal_cs_name, "[%s << /WhitePoint [1 1 1] >>]",
  194.             cs_name);
  195.         cs_name = cal_cs_name;
  196.         break;
  197.           case gs_color_space_index_CIEABC:
  198.           case gs_color_space_index_CIEDEF:
  199.         pdev->procsets |= ImageC;
  200.         cs_name = pin->CalRGB;
  201.         goto cal;
  202.           case gs_color_space_index_CIEDEFG:
  203.         pdev->procsets |= ImageC;
  204.         cs_name = pin->CalCMYK;
  205.         goto cal;
  206.           case gs_color_space_index_Indexed:
  207.         pdev->procsets |= ImageI;
  208.         pprints1(s, " [%s", pin->Indexed);
  209.         pip = &pcs->params.indexed;
  210.         pbcs = (const gs_color_space *)&pip->base_space;
  211.         indexed_decode[0] = 0;
  212.         indexed_decode[1] = (1 << pim->BitsPerComponent) - 1;
  213.         default_decode = indexed_decode;
  214.         goto csw;
  215.           default:
  216.         return_error(gs_error_rangecheck);
  217.           }
  218.         pprints1(s, " %s", cs_name);
  219.         num_components = gs_color_space_num_components(pbcs);
  220.         if ( pip )
  221.           { register const char _ds *hex_digits = "0123456789abcdef";
  222.         int i;
  223.  
  224.         pprintd1(s, " %d\n<", pip->hival);
  225.         for ( i = 0; i < (pip->hival + 1) * num_components; ++i )
  226.           { byte b = pip->lookup.table.data[i];
  227.             pputc(s, hex_digits[b >> 4]);
  228.             pputc(s, hex_digits[b & 0xf]);
  229.           }
  230.         pputs(s, ">\n]");
  231.         num_components = 1;
  232.           }
  233.       }
  234. /* Some compilers try to substitute macro args in string literals! */
  235. #define pprintsd(strm, str, v)\
  236.   (pprints1(strm, " %s", str), pprintd1(strm, " %d", v))
  237.     pprintsd(s, pin->Width, pim->Width);
  238.     pprintsd(s, pin->Height, pim->Height);
  239.     pprintsd(s, pin->BitsPerComponent, pim->BitsPerComponent);
  240. #undef pprintsd
  241.     { int i;
  242.       for ( i = 0; i < num_components * 2; ++i )
  243.         if ( pim->Decode[i] !=
  244.          (default_decode ? default_decode[i] : i & 1)
  245.            )
  246.           break;
  247.       if ( i < num_components * 2 )
  248.         { char sepr = '[';
  249.           pprints1(s, " %s ", pin->Decode);
  250.           for ( i = 0; i < num_components * 2; sepr = ' ', ++i )
  251.         { pputc(s, sepr);
  252.           pprintg1(s, "%g", pim->Decode[i]);
  253.         }
  254.           pputs(s, "]");
  255.         }
  256.     }
  257.     if ( pim->Interpolate )
  258.       pprints1(s, " %s true", pin->Interpolate);
  259.     if ( filter_name )
  260.       { if ( pdev->binary_ok )
  261.           pprints2(s, " %s [%s]", pin->Filter, filter_name);
  262.         else
  263.           pprints3(s, " %s [%s %s]", pin->Filter, pin->ASCII85Decode,
  264.                filter_name);
  265.         if ( decode_parms )
  266.           pprints2(s,
  267.                (pdev->binary_ok ? " %s [%s]" : " %s [null %s]"),
  268.                pin->DecodeParms, decode_parms);
  269.       }
  270.     else if ( !pdev->binary_ok )
  271.       pprints2(s, " %s [%s]", pin->Filter, pin->ASCII85Decode);
  272.     return 0;
  273. }
  274.  
  275. /* Fill in the image parameters for a device space bitmap. */
  276. /* PDF images are always specified top-to-bottom. */
  277. private void
  278. pdf_make_bitmap_matrix(gs_matrix *pmat, int x, int y, int w, int h)
  279. {    pmat->xx = w;
  280.     pmat->xy = 0;
  281.     pmat->yx = 0;
  282.     pmat->yy = -h;
  283.     pmat->tx = x;
  284.     pmat->ty = y + h;
  285. }
  286. private void
  287. pdf_make_bitmap_image(gs_image_t *pim, int x, int y, int w, int h)
  288. {    pim->Width = w;
  289.     pim->Height = h;
  290.     pdf_make_bitmap_matrix(&pim->ImageMatrix, x, y, w, h);
  291. }
  292.  
  293. /* Put out the gsave and matrix for an image. */
  294. private void
  295. pdf_put_image_matrix(gx_device_pdf *pdev, const gs_matrix *pmat)
  296. {    pprintg6(pdev->strm, "q\n%g %g %g %g %g %g cm\n",
  297.          pmat->xx / pdev->scale.x,
  298.          pmat->xy / pdev->scale.y,
  299.          pmat->yx / pdev->scale.x,
  300.          pmat->yy / pdev->scale.y,
  301.          pmat->tx / pdev->scale.x,
  302.          pmat->ty / pdev->scale.y);
  303. }
  304.  
  305. /* ------ Image writing ------ */
  306.  
  307. /* Define the structure for writing an image. */
  308. typedef struct pdf_image_writer_s {
  309.   pdf_binary_writer binary;
  310.   const pdf_image_names *pin;
  311.   const char *begin_data;
  312.   pdf_resource *pres;        /* XObject resource iff not in-line */
  313.   long length_id;        /* id of length object (forward reference) */
  314.   long start_pos;        /* starting file position of data */
  315. } pdf_image_writer;
  316.  
  317. /* Begin writing an image. */
  318. private int
  319. pdf_begin_write_image(gx_device_pdf *pdev, pdf_image_writer *piw, bool in_line)
  320. {    stream *s = pdev->strm;
  321.  
  322.     if ( in_line )
  323.       { piw->pres = 0;
  324.         pputs(s, "BI\n");
  325.         piw->pin = &image_names_short;
  326.         piw->begin_data = "ID ";
  327.       }
  328.     else
  329.       { int code = pdf_begin_resource(pdev, resourceXObject, &piw->pres);
  330.         if ( code < 0 )
  331.           return code;
  332.         piw->length_id = pdf_obj_ref(pdev);
  333.         pprintld1(s, " /Subtype /Image /Length %ld 0 R\n",
  334.               piw->length_id);
  335.         piw->pin = &image_names_full;
  336.         piw->begin_data = ">>\nstream\n";
  337.       }
  338.     return 0;
  339. }
  340.  
  341. /* Begin writing the image data. */
  342. private int
  343. pdf_begin_image_data(gx_device_pdf *pdev, pdf_image_writer *piw,
  344.   const gs_image_t *pim, const char *filter_name, const char *decode_parms)
  345. {    stream *s = pdev->strm;
  346.     int code = pdf_write_image_params(pdev, pim, filter_name, decode_parms,
  347.                       piw->pin);
  348.  
  349.     if ( code < 0 )
  350.       return code;
  351.     pprints1(s, "\n%s", piw->begin_data);
  352.     piw->start_pos = stell(s);
  353.     return 0;
  354. }
  355.  
  356. /* Finish writing an image. */
  357. /* Return 0 if resource, 1 if in-line, or an error code. */
  358. private int
  359. pdf_end_write_image(gx_device_pdf *pdev, pdf_image_writer *piw)
  360. {    stream *s = pdev->strm;
  361.  
  362.     if ( piw->pres )        /* image resource */
  363.       { long length;
  364.  
  365.         pputs(s, "\n");
  366.         length = stell(s) - piw->start_pos;
  367.         pputs(s, "endstream\n");
  368.         pdf_end_resource(pdev);
  369.         pdf_open_obj(pdev, piw->length_id);
  370.         pprintld1(s, "%ld\n", length);
  371.         pdf_end_obj(pdev);
  372.         return 0;
  373.       }
  374.     else        /* in-line image */
  375.       { pputs(s, "\nEI\nQ\n");
  376.         return 1;
  377.       }
  378. }
  379.  
  380. /* Put out a reference to an image resource. */
  381. private int
  382. pdf_do_image(gx_device_pdf *pdev, const pdf_resource *pres,
  383.   const gs_matrix *pimat)
  384. {    int code = pdf_open_contents(pdev, pdf_in_stream);
  385.  
  386.     if ( code < 0 )
  387.       return code;
  388.     if ( pimat )
  389.       pdf_put_image_matrix(pdev, pimat);
  390.     pprintld1(pdev->strm, "/R%ld Do\nQ\n", pres->id);
  391.     return 0;
  392. }
  393.  
  394. /* ---------------- Driver procedures ---------------- */
  395.  
  396. /* ------ Low-level calls ------ */
  397.  
  398. /* Copy a monochrome bitmap or mask. */
  399. int
  400. gdev_pdf_copy_mono(gx_device *dev,
  401.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  402.   int x, int y, int w, int h, gx_color_index zero, gx_color_index one)
  403. {    gx_device_pdf *pdev = (gx_device_pdf *)dev;
  404.     int code = pdf_open_page(pdev, pdf_in_stream);
  405.     gs_color_space cs;
  406.     byte palette[6];
  407.     gs_image_t image;
  408.     int yi;
  409.     pdf_image_writer writer;
  410.     pdf_resource *pres = 0;
  411.  
  412.     if ( code < 0 )
  413.       return code;
  414.     if ( w <= 0 || h <= 0 )
  415.       return 0;
  416.     /* Make sure we aren't being clipped. */
  417.     pdf_put_clip_path(pdev, NULL);
  418.     /* We have 3 cases: mask, inverse mask, and solid. */
  419.     if ( zero == gx_no_color_index )
  420.       { if ( one == gx_no_color_index )
  421.           return 0;
  422.         pdf_set_color(pdev, one, &pdev->fill_color, "rg");
  423.         /* If a mask has an id, assume it's a character. */
  424.         if ( id != gx_no_bitmap_id )
  425.           { pres = pdf_find_resource_by_gs_id(pdev, resourceXObject, id);
  426.         if ( pres == 0 )
  427.           { /* Define the character as an XObject resource. */
  428.             gs_image_t_init_mask(&image, true);
  429.             pdf_make_bitmap_image(&image, x, y, w, h);
  430.             code = pdf_begin_write_image(pdev, &writer, false);
  431.             if ( code >= 0 )
  432.               { writer.pres->rid = id;
  433.             goto wr;
  434.               }
  435.           }
  436.         if ( pres != 0 )
  437.           { pdf_make_bitmap_matrix(&image.ImageMatrix, x, y, w, h);
  438.             goto rx;
  439.           }
  440.           }
  441.         gs_image_t_init_mask(&image, true);
  442.       }
  443.     else if ( one == gx_no_color_index )
  444.       { gs_image_t_init_mask(&image, false);
  445.         pdf_set_color(pdev, zero, &pdev->fill_color, "rg");
  446.       }
  447.     else if ( zero == 0 && one == 0xffffff )
  448.       { gs_image_t_init_gray(&image);
  449.       }
  450.     else if ( zero == 0xffffff && one == 0 )
  451.       { gs_image_t_init_gray(&image);
  452.         image.Decode[0] = 1;
  453.         image.Decode[1] = 0;
  454.       }
  455.     else
  456.       { gs_image_t_init_color(&image);
  457.         cs.type = &gs_color_space_type_Indexed;
  458.         cs.params.indexed.hival = 1;
  459.         palette[0] = (byte)(zero >> 16);
  460.         palette[1] = (byte)(zero >> 8);
  461.         palette[2] = (byte)(zero);
  462.         palette[3] = (byte)(one >> 16);
  463.         palette[4] = (byte)(one >> 8);
  464.         palette[5] = (byte)(one);
  465.         cs.params.indexed.lookup.table.data = palette;
  466.         cs.params.indexed.lookup.table.size = 6;
  467.         cs.params.indexed.use_proc = false;
  468.         image.BitsPerComponent = 1;
  469.         image.ColorSpace = &cs;
  470.       }
  471.     /****** IGNORE sourcex ******/
  472.     pdf_make_bitmap_image(&image, x, y, w, h);
  473.     pdf_put_image_matrix(pdev, &image.ImageMatrix);
  474.     { ulong nbytes = (ulong)((w + 7) >> 3) * h;
  475.       code = pdf_begin_write_image(pdev, &writer, nbytes <= 4000);
  476.       if ( code < 0 )
  477.         return code;
  478.     }
  479. wr:    pres = writer.pres;
  480.     { char decode_parms[80];
  481.       sprintf(decode_parms,
  482.           "<< /K -1 /Columns %d /BlackIs1 true >>",
  483.           w);
  484.       pdf_begin_image_data(pdev, &writer, &image,
  485.                    writer.pin->CCITTFaxDecode, decode_parms);
  486.     }
  487.     { stream_CFE_state csstate;
  488.       csstate.template = &s_CFE_template;
  489.       (*csstate.template->set_defaults)((stream_state *)&csstate);
  490.       csstate.K = -1;
  491.       csstate.Columns = w;
  492.       csstate.Rows = h;
  493.       csstate.BlackIs1 = true;
  494.       pdf_begin_binary(pdev, &writer.binary, (stream_state *)&csstate);
  495.       for ( yi = 0; yi < h; ++yi )
  496.         { const byte *data = base + yi * raster;
  497.           uint nbytes = (w + 7) >> 3;
  498.           uint ignore;
  499.           sputs(writer.binary.strm, data, nbytes, &ignore);
  500.         }
  501.       pdf_end_binary(pdev, &writer.binary);
  502.     }
  503.     code = pdf_end_write_image(pdev, &writer);
  504.     switch ( code )
  505.       {
  506.       default: return code;        /* error */
  507.       case 1: return 0;
  508.       case 0: ;
  509.       }
  510. rx:    return pdf_do_image(pdev, pres, &image.ImageMatrix);
  511. }
  512.  
  513. /* Copy a color bitmap. */
  514. int
  515. gdev_pdf_copy_color(gx_device *dev,
  516.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  517.   int x, int y, int w, int h)
  518. {    gx_device_pdf *pdev = (gx_device_pdf *)dev;
  519.     int depth = dev->color_info.depth;
  520.     int bytes_per_pixel = depth >> 3;
  521.     int code = pdf_open_page(pdev, pdf_in_stream);
  522.     int yi;
  523.     gs_image_t image;
  524.     gs_color_space cs;
  525.     pdf_image_writer writer;
  526.     ulong nbytes;
  527.  
  528.     if ( code < 0 )
  529.       return code;
  530.     if ( w <= 0 || h <= 0 )
  531.       return 0;
  532.     /* Make sure we aren't being clipped. */
  533.     pdf_put_clip_path(pdev, NULL);
  534.     gs_image_t_init_color(&image);
  535.     pdf_make_bitmap_image(&image, x, y, w, h);
  536.     image.BitsPerComponent = 8;
  537.     cs.type = (bytes_per_pixel == 3 ? &gs_color_space_type_DeviceRGB :
  538.            bytes_per_pixel == 4 ? &gs_color_space_type_DeviceCMYK :
  539.            &gs_color_space_type_DeviceGray);
  540.     image.ColorSpace = &cs;
  541.     nbytes = (ulong)w * bytes_per_pixel * h;
  542.     pdf_put_image_matrix(pdev, &image.ImageMatrix);
  543.     code = pdf_begin_write_image(pdev, &writer, nbytes <= 4000);
  544.     if ( code < 0 )
  545.       return code;
  546.     code = pdf_begin_image_data(pdev, &writer, &image, NULL, NULL);
  547.     if ( code < 0 )
  548.       return code;
  549.     pdf_begin_binary(pdev, &writer.binary, NULL);
  550.     for ( yi = 0; yi < h; ++yi )
  551.       { uint ignore;
  552.         sputs(writer.binary.strm,
  553.           base + sourcex * bytes_per_pixel + yi * raster,
  554.           w * bytes_per_pixel, &ignore);
  555.       }
  556.     pdf_end_binary(pdev, &writer.binary);
  557.     code = pdf_end_write_image(pdev, &writer);
  558.     switch ( code )
  559.       {
  560.       default: return code;        /* error */
  561.       case 1: return 0;
  562.       case 0: ;
  563.       }
  564.     return pdf_do_image(pdev, writer.pres, &image.ImageMatrix);
  565. }
  566.  
  567. /* Fill a mask. */
  568. int
  569. gdev_pdf_fill_mask(gx_device *dev,
  570.   const byte *data, int data_x, int raster, gx_bitmap_id id,
  571.   int x, int y, int width, int height,
  572.   const gx_drawing_color *pdcolor, int depth,
  573.   gs_logical_operation_t lop, const gx_clip_path *pcpath)
  574. {    gx_device_pdf *pdev = (gx_device_pdf *)dev;
  575.     int code;
  576.  
  577.     if ( width <= 0 || height <= 0 )
  578.       return 0;
  579.     if ( depth > 1 || !gx_dc_is_pure(pdcolor) != 0 )
  580.       return gx_default_fill_mask(dev, data, data_x, raster, id,
  581.                       x, y, width, height, pdcolor, depth, lop,
  582.                       pcpath);
  583.     code = pdf_open_page(pdev, pdf_in_stream);
  584.     if ( code < 0 )
  585.       return code;
  586.     pdf_put_clip_path(pdev, pcpath);
  587.     return gdev_pdf_copy_mono(dev, data, data_x, raster, id,
  588.                   x, y, width, height,
  589.                   gx_no_color_index,
  590.                   gx_dc_pure_color(pdcolor));
  591. }
  592.  
  593. /* ------ High-level calls ------ */
  594.  
  595. /* Define the structure for keeping track of progress through an image. */
  596. typedef struct pdf_image_enum_s {
  597.     gs_memory_t *memory;
  598.     void *default_info;
  599.     int width;
  600.     int num_planes;
  601.     int bits_per_pixel;    /* bits per pixel (per plane) */
  602.     int rows_left;
  603.     pdf_image_writer writer;
  604. } pdf_image_enum;
  605. /* We can disregard the pointers in the writer by allocating */
  606. /* the image enumerator as immovable.  This is a hack, of course. */
  607. gs_private_st_ptrs1(st_pdf_image_enum, pdf_image_enum, "pdf_image_enum",
  608.   pdf_image_enum_enum_ptrs, pdf_image_enum_reloc_ptrs, default_info);
  609.  
  610. /* Test whether we can handle a given color space. */
  611. private bool
  612. pdf_can_handle_color_space(const gs_color_space *pcs)
  613. {    gs_color_space_index index = gs_color_space_get_index(pcs);
  614.     if ( index == gs_color_space_index_Indexed )
  615.       { if ( pcs->params.indexed.use_proc )
  616.           return false;
  617.         index =
  618.           gs_color_space_get_index(gs_color_space_indexed_base_space(pcs));
  619.       }
  620.     return !(index == gs_color_space_index_Separation ||
  621.          index == gs_color_space_index_Pattern);
  622. }
  623.  
  624. /* Start processing an image. */
  625. int
  626. gdev_pdf_begin_image(gx_device *dev,
  627.   const gs_imager_state *pis, const gs_image_t *pim,
  628.   gs_image_format_t format, const gs_int_rect *prect,
  629.   const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
  630.   gs_memory_t *mem, void **pinfo)
  631. {    gx_device_pdf *pdev = (gx_device_pdf *)dev;
  632.     int code = pdf_open_page(pdev, pdf_in_stream);
  633.     pdf_image_enum *pie;
  634.     const gs_color_space *pcs = pim->ColorSpace;
  635.     int num_components =
  636.       (pim->ImageMask ? 1 : gs_color_space_num_components(pcs));
  637.     gs_int_rect rect;
  638.     ulong nbytes;
  639.  
  640.     if ( code < 0 )
  641.       return code;
  642.     if ( prect )
  643.       rect = *prect;
  644.     else
  645.       { rect.p.x = rect.p.y = 0;
  646.         rect.q.x = pim->Width, rect.q.y = pim->Height;
  647.       }
  648.     /* See above for why we allocate the enumerator as immovable. */
  649.     pie = gs_alloc_struct_immovable(mem, pdf_image_enum,
  650.                     &st_pdf_image_enum,
  651.                     "pdf_begin_image");
  652.     if ( pie == 0 )
  653.       return_error(gs_error_VMerror);
  654.     pie->memory = mem;
  655.     *pinfo = pie;
  656.     if ( (pim->ImageMask ?
  657.           (!gx_dc_is_pure(pdcolor) || pim->CombineWithColor) :
  658.           !pdf_can_handle_color_space(pim->ColorSpace)) ||
  659.          prect
  660.        )
  661.         { int code = gx_default_begin_image(dev, pis, pim, format, prect,
  662.                         pdcolor, pcpath, mem,
  663.                         &pie->default_info);
  664.           if ( code < 0 )
  665.         gs_free_object(mem, pie, "pdf_begin_image");
  666.           return code;
  667.         }
  668.     pie->default_info = 0;
  669.     pie->width = rect.q.x - rect.p.x;
  670.     switch ( format )
  671.       {
  672.       case gs_image_format_chunky:
  673.         pie->num_planes = 1; break;
  674.       case gs_image_format_component_planar:
  675.         pie->num_planes = num_components; break;
  676.       case gs_image_format_bit_planar:
  677.         pie->num_planes = num_components * pim->BitsPerComponent; break;
  678.       }
  679.     pie->bits_per_pixel =
  680.       pim->BitsPerComponent * num_components / pie->num_planes;
  681.     pie->rows_left = rect.q.y - rect.p.y;
  682.     pdf_put_clip_path(pdev, pcpath);
  683.     if ( pim->ImageMask )
  684.       pdf_set_color(pdev, gx_dc_pure_color(pdcolor), &pdev->fill_color,
  685.             "rg");
  686.     /****** DOESN'T DO COMPRESSION YET ******/
  687.     { gs_matrix mat;
  688.       gs_matrix bmat;
  689.       int code;
  690.  
  691.       pdf_make_bitmap_matrix(&bmat, -rect.p.x, -rect.p.y,
  692.                  pim->Width, pim->Height);
  693.       if ( (code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
  694.            (code = gs_matrix_multiply(&bmat, &mat, &mat)) < 0 ||
  695.            (code = gs_matrix_multiply(&mat, &ctm_only(pis), &mat)) < 0
  696.          )
  697.         { gs_free_object(mem, pie, "pdf_begin_image");
  698.           return code;
  699.         }
  700.       pdf_put_image_matrix(pdev, &mat);
  701.     }
  702.     nbytes = (((ulong)pie->width * pie->bits_per_pixel + 7) >> 3) *
  703.       pie->rows_left;
  704.     code = pdf_begin_write_image(pdev, &pie->writer, nbytes <= 4000);
  705.     if ( code < 0 )
  706.       return code;
  707.     code = pdf_begin_image_data(pdev, &pie->writer, pim, NULL, NULL);
  708.     if ( code < 0 )
  709.       return code;
  710.     pdf_begin_binary(pdev, &pie->writer.binary, NULL);
  711.     return 0;
  712. }
  713.  
  714. /* Process the next piece of an image. */
  715. int
  716. gdev_pdf_image_data(gx_device *dev,
  717.   void *info, const byte **planes, int data_x, uint raster, int height)
  718. {    pdf_image_enum *pie = info;
  719.     int h = height;
  720.     uint y_offset = 0;
  721.     uint bcount;
  722.     uint ignore;
  723.     int nplanes = pie->num_planes;
  724. #define row_bytes 180        /* must be 0 mod 3, 4, 6, 9 */
  725.     byte row[row_bytes];
  726.  
  727.     if ( pie->default_info )
  728.       return gx_default_image_data(dev, pie->default_info, planes, data_x,
  729.                        raster, height);
  730.     if ( h > pie->rows_left )
  731.       h = pie->rows_left;
  732.     pie->rows_left -= h;
  733.     bcount = ((data_x + pie->width) * pie->bits_per_pixel + 7) >> 3;
  734.     for ( ; h > 0; y_offset += raster, --h )
  735.       { if ( nplanes > 1 )
  736.           { /* Flip the data in blocks before writing. */
  737.         uint offset = y_offset;
  738.         uint count = bcount;
  739.  
  740.         while ( count )
  741.           { uint flip_count = min(count, row_bytes / nplanes);
  742.             image_flip_planes(row, planes, offset, flip_count, nplanes,
  743.                       pie->bits_per_pixel);
  744.             sputs(pie->writer.binary.strm, row, flip_count * nplanes,
  745.               &ignore);
  746.             count -= flip_count;
  747.             offset += flip_count;
  748.           }
  749.           }
  750.         else
  751.           sputs(pie->writer.binary.strm, planes[0] + y_offset, bcount,
  752.             &ignore);
  753.       }
  754.     return !pie->rows_left;
  755. #undef row_bytes
  756. }
  757.  
  758. /* Clean up by releasing the buffers. */
  759. int
  760. gdev_pdf_end_image(gx_device *dev, void *info, bool draw_last)
  761. {    gx_device_pdf *pdev = (gx_device_pdf *)dev;
  762.     pdf_image_enum *pie = info;
  763.     int code;
  764.  
  765.     if ( pie->default_info )
  766.       code = gx_default_end_image(dev, pie->default_info, draw_last);
  767.     else
  768.       { code = pdf_end_binary(pdev, &pie->writer.binary);
  769.         if ( code < 0 )
  770.           return code;
  771.         code = pdf_end_write_image(pdev, &pie->writer);
  772.         switch ( code )
  773.           {
  774.           default: return code;        /* error */
  775.           case 1: return 0;
  776.           case 0: ;
  777.           }
  778.         code = pdf_do_image(pdev, pie->writer.pres, NULL);
  779.       }
  780.     gs_free_object(pie->memory, pie, "pdf_end_image");
  781.     return code;
  782. }
  783.